<?php

namespace App\CustHub\Service;

use App\Common\Constants\SmsEventConstants;
use App\Common\Service\SmsService;
use App\Common\Service\WkyService;
use App\CustHub\Interfaces\ChUserAuthServiceInterface;
use App\CustHub\Mapper\ChUserMapper;
use App\Setting\Service\SettingConfigService;
use App\CustHub\Vo\ChUserServiceVo;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Container;
use Hyperf\Redis\Redis;
use Hyperf\Redis\RedisFactory;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;

class WxOauthService extends AbstractService
{
    #[Inject]
    protected ChUserService $userService;

    #[Inject]
    protected ChUserMapper $chUserMapper;

    #[Inject]
    protected ChUserAuthServiceInterface $userAuthService;

    #[Inject]
    protected WkyService $wkyService;

    #[Inject]
    protected Redis $redis;

    /**
     * 获取登录二维码
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getLoginQrCode()
    {
        $officialId = container()->get(SettingConfigService::class)->getConfigByKey('wky_official_id')['value'] ?? 106;
        $response = $this->wkyService->getLoginQrCode($officialId);

        $uuid = $response['uuid'];
        $login_id = 'CustHubLogIn_' . $uuid;

        $data = [
            'uuid'       => $uuid,
            'uid'        => '',
            'openid'     => '',
            'invitecode' => ''
        ];

        //数据缓存300秒用以用户完善信息
        $this->redis->set($login_id, $data, 300);
        //缓存扫码登录标识用于checkQrLogin判断二维码是否过期
        $this->redis->set('CustHubScan_Code_'.$uuid, 1,  60);
        return [
            'qr_url' => $response['qr_url'],
            'login_id' => auth_code($login_id,'ENCODE')
        ];
    }

    /**
     * 检查扫码登录状态
     * @param $param
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    public function checkQrLogin($param): array
    {
        $loginId = auth_code($param['login_id']);

        $cache = $this->redis->get($loginId);

        $login_tag = 'CustHubScan_Code_' . str_replace('CustHubLogIn_', '', $cache['uuid']);
        if (!$this->redis->get($login_tag)) {
            return ['msg' => '登录失败，请尝试刷新二维码重新扫描', 'result' => ['page' => 'reset']];
        }

        if ($cache['openid']) {
            //获取用户信息
            $user = $this->chUserMapper->findByOpenid($cache['openid']);

            if ($user && $user['mobile']) {
                //进即将成功登录页面，页面请求checkUser方法
                return [
                    'msg' => '扫码成功，进入登录页面',
                    'result' => ['page' => 'login', 'login_id' => $param['login_id'], 'openid' => $user['openid']]
                ];
            } else {
                //进入绑定手机号页面，确认绑定手机号请求bindMobile方法
                $needPassword = empty($user) ? 1 : 0;
                return [
                    'msg' => '扫码成功，绑定手机号页面',
                    'result' => [
                        'page' => 'bind',
                        'login_id' => $param['login_id'],
                        'openid' => $cache['openid'],
                        'need_pass' => $needPassword
                    ]
                ];
            } 
        } else {
            return [
                'msg' => '继续定时请求',
                'result' => null
            ];
        }
    }

    /**
     *扫 码登录，如已绑定手机号则验证用户信息并返回用户数据
     * @param $param
     * @return mixed
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    public function checkUser($param)
    {
        $loginId = $param['login_id'];
        $openid = $param['openid'];

        //根据扫码的参数$login_id从缓存里获取数据
        $login_id = auth_code($loginId);
        $cache = $this->redis->get($login_id);
        if (!$cache || $cache['openid'] != $openid) {
            throw new NormalStatusException('登录失败，请尝试刷新二维码重新扫描');
        }

        $userServiceVo = new ChUserServiceVo();
        $userServiceVo->setOpenid($openid);
        $result = $this->userAuthService->login($userServiceVo);
        $this->redis->del($login_id);
        return $result;
    }

    /**
     * 绑定手机号
     * @param $param
     * @return mixed
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    #[Transaction]
    public function bindMobile($param): mixed
    {
        //根据扫码的参数$login_id从缓存里获取数据
        $login_id = auth_code($param['login_id']);
        $cache = $this->redis->get($login_id);
        if (!$cache || $cache['openid'] != $param['openid']) {
            throw new NormalStatusException('登录失败，请尝试刷新二维码重新扫描');
        }

        if (!$param['openid']) {
            throw new NormalStatusException('授权信息获取失败');
        }

        $inviteId = 0;
        if($this->userAuthService->checkInviteCodeNeed($param['mobile'])){
            // 判断是否需要邀请码 且填写了邀请码
            if(empty($param['invite_code'])){
                throw new NormalStatusException('请填写邀请码');
            }

            $inviteUserInfo = $this->mapper->findByInviteCode($param['invite_code']);
            if(empty($inviteUserInfo)){
                throw new NormalStatusException('邀请码无效');
            }

            $inviteId = $inviteUserInfo->id;
        }

        //验证手机验证码
        $smsService = make(SmsService::class,[SmsEventConstants::CH_BIND_MOBILE]);
        if (!$smsService->verifyCode($param['mobile'], $param['code'])) {
            throw new NormalStatusException('验证码错误');
        }

        //验证手机号是否存在
        if ($this->userService->checkUserMobileExist($param['mobile'])) {
            throw new NormalStatusException('该手机号已被绑定');
        }

        //获取用户信息
        $info = $this->chUserMapper->findByOpenid($cache['openid']);
        if (!empty($info)) {
            //兼容老版逻辑 存在账号 绑定手机号
            $u_data = [
                'account' => $param['mobile'],
                'mobile' => $param['mobile'],
            ];
            //开始更新
            $up_res = $this->userService->update($info['id'],$u_data);
            if(!$up_res){
                throw new NormalStatusException('手机号绑定失败');
            }
        }else{
            $info = $this->chUserMapper->findByMobile($param['mobile']);
            if(!empty($info)){
                //存在账号 更新openid unionid
                $u_data = [
                    'openid' => $param['openid'],
                    'unionid'    => $cache['unionid'] ?? '',
                ];
                //开始更新
                $up_res = $this->userService->update($info['id'],$u_data);
                if(!$up_res){
                    throw new NormalStatusException('手机号绑定失败');
                }
            }else{
                $password = $param['password'] ?? 'wky@123456';
                $this->userService->register($param['mobile'],$param['openid'],$cache['unionid'],$password,$inviteId);
            }
        }

        $userServiceVo = new ChUserServiceVo();
        $userServiceVo->setOpenid($cache['openid']);
        $result = $this->userAuthService->login($userServiceVo);
        $this->redis->del($login_id);
        return $result;
    }
}